#ifndef __HTTP_HEADER__
#define __HTTP_HEADER__

#include <sys/types.h> 
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>

#define HTTP_HEADER_ACCEPT                     "Accept"
#define HTTP_HEADER_ACCEPT_CHARSET             "Accept-Charset"
#define HTTP_HEADER_ACCEPT_ENCODING            "Accept-Encoding"
#define HTTP_HEADER_ACCEPT_LANGUAGE            "Accept-Language"
#define HTTP_HEADER_ACCEPT_RANGES              "Accept-Ranges"
#define HTTP_HEADER_AGE                        "Age"
#define HTTP_HEADER_ALLOW                      "Allow"
#define HTTP_HEADER_AUTHORIZATION              "Authorization"        /* for now */
#define HTTP_HEADER_CACHE_CONTROL              "Cache-Control"
#define HTTP_HEADER_CONNECTION                 "Connection"
#define HTTP_HEADER_CONTENT_BASE               "Content-Base"
#define HTTP_HEADER_CONTENT_ENCODING           "Content-Encoding"
#define HTTP_HEADER_CONTENT_LANGUAGE           "Content-Language"
#define HTTP_HEADER_CONTENT_LENGTH             "Content-Length"
#define HTTP_HEADER_CONTENT_LOCATION           "Content-Location"
#define HTTP_HEADER_CONTENT_MD5                "Content-MD5"         /* for now */
#define HTTP_HEADER_CONTENT_RANGE              "Content-Range"
#define HTTP_HEADER_CONTENT_TYPE               "Content-Type"
#define HTTP_HEADER_COOKIE                     "Cookie"
#define HTTP_HEADER_DATE                       "Date"
#define HTTP_HEADER_ETAG                       "ETag"
#define HTTP_HEADER_EXPIRES                    "Expires"
#define HTTP_HEADER_FROM                       "From"
#define HTTP_HEADER_HOST                       "Host"
#define HTTP_HEADER_IF_MATCH                   "If-Match"           /* for now */
#define HTTP_HEADER_IF_MODIFIED_SINCE          "If-Modified-Since"
#define HTTP_HEADER_IF_NONE_MATCH              "If-None-Match"      /* for now */
#define HTTP_HEADER_IF_RANGE                   "If-Range"
#define HTTP_HEADER_LAST_MODIFIED              "Last-Modified"
#define HTTP_HEADER_LINK                       "Link"
#define HTTP_HEADER_LOCATION                   "Location"
#define HTTP_HEADER_MAX_FORWARDS               "Max-Forwards"
#define HTTP_HEADER_MIME_VERSION               "Mime-Version"       /* for now */
#define HTTP_HEADER_PRAGMA                     "Pragma"
#define HTTP_HEADER_PROXY_AUTHENTICATE         "Proxy-Authenticate"
#define HTTP_HEADER_PROXY_AUTHENTICATION_INFO  "Proxy-Authentication-Info"
#define HTTP_HEADER_PROXY_AUTHORIZATION        "Proxy-Authorization"
#define HTTP_HEADER_PROXY_CONNECTION           "Proxy-Connection"
#define HTTP_HEADER_PUBLIC                     "Public"
#define HTTP_HEADER_RANGE                      "Range"
#define HTTP_HEADER_REFERER                    "Referer"
#define HTTP_HEADER_REQUEST_RANGE              "Request-Range"     /* usually matches HTTP_HEADER_RANGE */
#define HTTP_HEADER_RETRY_AFTER                "Retry-After"       /* for now (ftDate_1123 or ftInt!) */
#define HTTP_HEADER_SERVER                     "Server"
#define HTTP_HEADER_SET_COOKIE                 "Set-Cookie"
#define HTTP_HEADER_TITLE                      "Title"
#define HTTP_HEADER_UPGRADE                    "Upgrade"           /* for now */
#define HTTP_HEADER_USER_AGENT                 "User-Agent"
#define HTTP_HEADER_VARY                       "Vary"              /* for now */
#define HTTP_HEADER_VIA                        "Via"               /* for now */
#define HTTP_HEADER_WARNING                    "Warning"           /* for now */
#define HTTP_HEADER_WWW_AUTHENTICATE           "WWW-Authenticate"
#define HTTP_HEADER_AUTHENTICATION_INFO        "Authentication-Info"
#define HTTP_HEADER_X_CACHE                    "X-Cache"
#define HTTP_HEADER_X_CACHE_LOOKUP             "X-Cache-Lookup"
#define HTTP_HEADER_X_FORWARDED_FOR            "X-Forwarded-For"
#define HTTP_HEADER_X_REQUEST_URI              "X-Request-URI"
#define HTTP_HEADER_X_SQUID_ERROR              "X-Squid-Error"
#define HTTP_HEADER_OTHER                      "Other"              /* ':' will not allow matches */

/**
 * @defgroup HTTP_Status HTTP Status Codes
 */
#define HTTP_CONTINUE                      100
#define HTTP_SWITCHING_PROTOCOLS           101
#define HTTP_PROCESSING                    102
#define HTTP_OK                            200
#define HTTP_CREATED                       201
#define HTTP_ACCEPTED                      202
#define HTTP_NON_AUTHORITATIVE             203
#define HTTP_NO_CONTENT                    204
#define HTTP_RESET_CONTENT                 205
#define HTTP_PARTIAL_CONTENT               206
#define HTTP_MULTI_STATUS                  207
#define HTTP_MULTIPLE_CHOICES              300
#define HTTP_MOVED_PERMANENTLY             301
#define HTTP_MOVED_TEMPORARILY             302
#define HTTP_SEE_OTHER                     303
#define HTTP_NOT_MODIFIED                  304
#define HTTP_USE_PROXY                     305
#define HTTP_TEMPORARY_REDIRECT            307
#define HTTP_BAD_REQUEST                   400
#define HTTP_UNAUTHORIZED                  401
#define HTTP_PAYMENT_REQUIRED              402
#define HTTP_FORBIDDEN                     403
#define HTTP_NOT_FOUND                     404
#define HTTP_METHOD_NOT_ALLOWED            405
#define HTTP_NOT_ACCEPTABLE                406
#define HTTP_PROXY_AUTHENTICATION_REQUIRED 407
#define HTTP_REQUEST_TIME_OUT              408
#define HTTP_CONFLICT                      409
#define HTTP_GONE                          410
#define HTTP_LENGTH_REQUIRED               411
#define HTTP_PRECONDITION_FAILED           412
#define HTTP_REQUEST_ENTITY_TOO_LARGE      413
#define HTTP_REQUEST_URI_TOO_LARGE         414
#define HTTP_UNSUPPORTED_MEDIA_TYPE        415
#define HTTP_RANGE_NOT_SATISFIABLE         416
#define HTTP_EXPECTATION_FAILED            417
#define HTTP_UNPROCESSABLE_ENTITY          422
#define HTTP_LOCKED                        423
#define HTTP_FAILED_DEPENDENCY             424
#define HTTP_UPGRADE_REQUIRED              426
#define HTTP_INTERNAL_SERVER_ERROR         500
#define HTTP_NOT_IMPLEMENTED               501
#define HTTP_BAD_GATEWAY                   502
#define HTTP_SERVICE_UNAVAILABLE           503
#define HTTP_GATEWAY_TIME_OUT              504
#define HTTP_VERSION_NOT_SUPPORTED         505
#define HTTP_VARIANT_ALSO_VARIES           506
#define HTTP_INSUFFICIENT_STORAGE          507
#define HTTP_NOT_EXTENDED                  510


/** The timeout for waiting for messages */
#ifndef DEFAULT_TIMEOUT
#define DEFAULT_TIMEOUT 300
#endif

/** The timeout for waiting for keepalive timeout until next request */
#ifndef DEFAULT_KEEPALIVE_TIMEOUT
#define DEFAULT_KEEPALIVE_TIMEOUT 5
#endif

/** The number of requests to entertain per connection */
#ifndef DEFAULT_KEEPALIVE
#define DEFAULT_KEEPALIVE 100
#endif

/*
 * Limits on the size of various request items.  These limits primarily
 * exist to prevent simple denial-of-service attacks on a server based
 * on misuse of the protocol.  The recommended values will depend on the
 * nature of the server resources -- CGI scripts and database backends
 * might require large values, but most servers could get by with much
 * smaller limits than we use below.  The request message body size can
 * be limited by the per-dir config directive LimitRequestBody.
 *
 * Internal buffer sizes are two bytes more than the DEFAULT_LIMIT_REQUEST_LINE
 * and DEFAULT_LIMIT_REQUEST_FIELDSIZE below, which explains the 8190.
 * These two limits can be lowered (but not raised) by the server config
 * directives LimitRequestLine and LimitRequestFieldsize, respectively.
 *
 * DEFAULT_LIMIT_REQUEST_FIELDS can be modified or disabled (set = 0) by
 * the server config directive LimitRequestFields.
 */

/** default limit on bytes in Request-Line (Method+URI+HTTP-version) */
#ifndef DEFAULT_LIMIT_REQUEST_LINE
#define DEFAULT_LIMIT_REQUEST_LINE 8190
#endif

/** default limit on bytes in any one header field  */
#ifndef DEFAULT_LIMIT_REQUEST_FIELDSIZE
#define DEFAULT_LIMIT_REQUEST_FIELDSIZE 8190
#endif

/** default limit on number of request header fields */
#ifndef DEFAULT_LIMIT_REQUEST_FIELDS
#define DEFAULT_LIMIT_REQUEST_FIELDS 100
#endif

#ifndef DEFAULT_LIMIT_REQUEST_DATASIZE
#define DEFAULT_LIMIT_REQUEST_DATASIZE 32768
#endif

#ifndef DEFAULT_LIMIT_RESPONSE_DATASIZE
#define DEFAULT_LIMIT_RESPONSE_DATASIZE 32768
#endif

/**
 * The default default character set name to add if AddDefaultCharset is
 * enabled.  Overridden with AddDefaultCharsetName.
 */
#define DEFAULT_ADD_DEFAULT_CHARSET_NAME "iso-8859-1"

/** default HTTP Server protocol */
#define DEFAULT_SERVER_PROTOCOL "HTTP/1.1"

/**
 * Define this to be what type you'd like returned for files with unknown
 * suffixes.
 * @warning MUST be all lower case.
 */
#ifndef DEFAULT_CONTENT_TYPE
#define DEFAULT_CONTENT_TYPE "text/plain"
#endif

/** is the status code informational */
#define is_HTTP_INFO(x)         (((x) >= 100)&&((x) < 200))
/** is the status code OK ?*/
#define is_HTTP_SUCCESS(x)      (((x) >= 200)&&((x) < 300))
/** is the status code a redirect */
#define is_HTTP_REDIRECT(x)     (((x) >= 300)&&((x) < 400))
/** is the status code a error (client or server) */
#define is_HTTP_ERROR(x)        (((x) >= 400)&&((x) < 600))
/** is the status code a client error  */
#define is_HTTP_CLIENT_ERROR(x) (((x) >= 400)&&((x) < 500))
/** is the status code a server error  */
#define is_HTTP_SERVER_ERROR(x) (((x) >= 500)&&((x) < 600))
/** is the status code a (potentially) valid response code?  */
#define is_HTTP_VALID_RESPONSE(x) (((x) >= 100)&&((x) < 600))

/** should the status code drop the connection */
#define status_drops_connection(x) \
		(((x) == HTTP_BAD_REQUEST)           || \
		((x) == HTTP_REQUEST_TIME_OUT)      || \
		((x) == HTTP_LENGTH_REQUIRED)       || \
		((x) == HTTP_REQUEST_ENTITY_TOO_LARGE) || \
		((x) == HTTP_REQUEST_URI_TOO_LARGE) || \
		((x) == HTTP_INTERNAL_SERVER_ERROR) || \
		((x) == HTTP_SERVICE_UNAVAILABLE) || \
		((x) == HTTP_NOT_IMPLEMENTED))

/** @} */
/* Just in case your linefeed isn't the one the other end is expecting. */
#if !CHARSET_EBCDIC
/** linefeed */
#define LF 10
/** carrige return */
#define CR 13
/** carrige return /Line Feed Combo */
#define CRLF "\015\012"
#else /* APR_CHARSET_EBCDIC */
/* For platforms using the EBCDIC charset, the transition ASCII->EBCDIC is done
 * in the buff package (bread/bputs/bwrite).  Everywhere else, we use
 * "native EBCDIC" CR and NL characters. These are therefore
 * defined as
 * '\r' and '\n'.
 */
#define CR '\r'
#define LF '\n'
#define CRLF "\r\n"
#endif /* APR_CHARSET_EBCDIC */

/**
 * @defgroup values_request_rec_body Possible values for request_rec.read_body
 * @{
 * Possible values for request_rec.read_body (set by handling module):
 */

/** Send 413 error if message has any body */
#define REQUEST_NO_BODY          0
/** Send 411 error if body without Content-Length */
#define REQUEST_CHUNKED_ERROR    1
/** If chunked, remove the chunks for me. */
#define REQUEST_CHUNKED_DECHUNK  2
/** @} // values_request_rec_body */


/** HTTP / DAV method **/
typedef enum
{
	HTTP_METHOD_GET,
	HTTP_METHOD_POST,
	HTTP_METHOD_HEAD,
	HTTP_METHOD_OPTIONS,
	HTTP_METHOD_PROPFIND,  /* WebDAV */
	HTTP_METHOD_MKCOL,
	HTTP_METHOD_PUT,
	HTTP_METHOD_DELETE,
	HTTP_METHOD_COPY,
	HTTP_METHOD_MOVE,
	HTTP_METHOD_PROPPATCH,
	HTTP_METHOD_REPORT, /* DeltaV */
	HTTP_METHOD_CHECKOUT,
	HTTP_METHOD_CHECKIN,
	HTTP_METHOD_VERSION_CONTROL,
	HTTP_METHOD_UNCHECKOUT,
	HTTP_METHOD_MKACTIVITY,
	HTTP_METHOD_MERGE,
	HTTP_METHOD_LOCK,
	HTTP_METHOD_UNLOCK,
	HTTP_METHOD_LABEL,
	HTTP_METHOD_CONNECT,
	HTTP_METHOD_UNSET = -1
}
http_method_t;

typedef enum { HTTP_VERSION_1_0, HTTP_VERSION_1_1, HTTP_VERSION_UNSET = -1} http_version_t;

typedef enum { HTTP_AUTH_BASIC, HTTP_AUTH_DIGEST } httpauth_type_t;

typedef struct {
	int key;
	char *value;
}
key_value;

typedef struct _httpd_var {
	char	*name,
		*value;
	struct	_httpd_var *next;
}
http_var;

typedef struct _http_request {
	http_method_t method;
	http_version_t version;
	char *uri;
	char *path;
	http_var *header_entry;
	int content_length;
	char *content;
}
http_request;

typedef struct _http_response {
	int code;
	http_version_t version;
	http_var *header_entry;
	int content_length;
	char *content;
}
http_response;

typedef struct {
	int fd;
	struct sockaddr_in addr;
	socklen_t length;	
}
http_client;

typedef enum
{
	CONNE_BUFSTAT_UNSET = -1,
	CONNE_BUFSTAT_READY,
	CONNE_BUFSTAT_FULL,
	CONNE_BUFSTAT_END,
	CONNE_BUFSTAT_FAILED
}
buf_stat_type;

typedef struct
{
	http_client   client;
	http_request  request;
	http_response response;
	
	char readbuf[DEFAULT_LIMIT_REQUEST_LINE + 1];
	char *rptr;
	
	int bufpos;
	int bufsize;
	buf_stat_type bufstat;
	
	int keep_alive;	/* only request.c can enable it, all other just disable */
}
connection;

const char* http_get_error(int key);

ssize_t httpd_read(int fd, char *vptr, size_t len);

ssize_t httpd_readline(connection* conn, char *vptr, size_t len);

ssize_t httpd_write(int fd, const void *vptr, size_t len);

int  http_conn_init(connection* conn, const http_client *cli);
void http_conn_fini(connection* conn);

extern int httpd_var_append(http_var *vptr, const char *name, size_t sn, const char *value, size_t sv);

extern http_var *httpd_var_end(http_var *vptr);

extern const char* http_var_get(http_var *var, const char* name);

extern void http_var_free(http_var **entry);

extern int http_cookie_parse (const char *str, size_t len, http_var **entry);

extern int http_request_parse(connection* conn);

extern int http_request_call (http_request* req, int timeout, char *resp, int len);

extern int http_response_call(connection* conn);

extern int http_listen(int port, int theards);

#endif // __HTTP_HEADER__
